#include "BlockBreakParticleBehavior.h"

#include "App/Game.h"
#include "Asset/AssetManager.h"
#include "Util/Random.h"
#include "World/World.h"


BlockBreakParticleSystem::BlockBreakParticleSystem()
    : cubeShader(AssetManager::LoadAsset<Shader>("assets/shaders/src/ColoredCubeOpaque")) {}

void BlockBreakParticleSystem::Render(glm::mat4 MVP)
{
  cubeShader->Bind();

  for (const auto &particle : m_particles)
  {
    cubeShader->SetVec4("uColor", particle.color);
    cubeShader->SetMat4("uMVP", MVP * glm::translate(particle.position) * glm::scale(particle.scale) *
                                    glm::rotate(glm::two_pi<float>(), particle.rotation));
    cubeMesh.Render();
  }
}

void BlockBreakParticleBehavior::OnBlockBreak(Player *player, glm::ivec3 blockPos, const BlockData *block, World &world)
{
  if (!player)
    return;

  if (block == nullptr || block->id == 0)
    return;

  auto reg = Game::GetInstance().GetLevel()->GetBlockRegistry();
  auto color = reg->GetBlock(block->id)->color;
  for (int i = 0; i < 50; ++i)
  {
    EmitBlockParticle(glm::vec3(blockPos) + Util::RandVec3(), color);
  }
}

void BlockBreakParticleBehavior::EmitBlockParticle(glm::vec3 pos, glm::vec4 color)
{
  particleSystem.Emit({
      .position = pos,
      .scale = glm::vec3(0.0625),
      .scaleVelocity = glm::vec3(-0.0625),
      .scaleVelocityVariation = glm::vec3(.05),
      .velocity = glm::vec3(1, 0, 1),
      .velocityVariation = glm::vec3(-2, 1, -2),
      .gravity = glm::vec3(0, -9.8, 0),
      .rotation = glm::vec3(0),
      .angularVelocity = glm::vec3(1, -1, 1),
      .angularVelocityVariation = glm::vec3(.25, .25, .25),
      .startColor = color,
      .endColor = color,
      .startLifetime = .200,
      .lifetimeVariation = .200,
      .lifetime = .200,
  });
}

void BlockBreakParticleBehavior::Update(float dt)
{
  particleSystem.Update(dt);
}

void BlockBreakParticleBehavior::RenderOpaque(glm::mat4 transform, glm::vec3 playerPos, const Frustum &frustum)
{
  particleSystem.Render(transform);
}
